package com.jeasonzhao.report.model;

import com.jeasonzhao.commons.json.JSONArray;
import com.jeasonzhao.commons.json.JSONClass;
import com.jeasonzhao.commons.utils.Algorithms;
import com.jeasonzhao.commons.utils.DataTypes;
import com.jeasonzhao.commons.xml.XMLNode;
import com.jeasonzhao.model.Model;
import com.jeasonzhao.model.ModelException;
import com.jeasonzhao.model.ModelField;
import com.jeasonzhao.report.codes.ReportDictTypes;

@Model("Dict")
public class ReportDict extends BaseReportModelItem
{
	private static final long serialVersionUID = 1L;
	@ModelField(names = "id,key")
    private String dictId = null;

    @ModelField(names = "name,title")
    private String dictName = null;

    @ModelField(names = "parentId,pkey,pid,parentKey")
    private String parentId = null;

    @ModelField(names = "dicttype,type")
    private ReportDictTypes dictType = ReportDictTypes.External;

    @ModelField(names = "databaseid,dbid,database")
    private String databaseId = null;

    @ModelField(names = "sql,sqlstatement,statement",cdata = true)
    private String sqlStatement = null;

    @ModelField(names = "datatype,keydatatype,keytype")
    private DataTypes m_keyDataType = null;

    @ModelField(names = "param,parameter",forceNode = true)
    private String m_appendParam = null;

    private DictItemCollection m_items = null;

    public ReportDict()
    {

    }

    public String getParameter()
    {
        return m_appendParam;
    }

    public void setParameter(String v)
    {
        this.m_appendParam = v;
    }

    public void setDictItems(DictItemCollection otems)
    {
        m_items = otems;
    }

    public DictItemCollection getItems()
    {
        return m_items == null || m_items.size() < 1 ? null : m_items;
    }

    public int getItemsCount()
    {
        return m_items == null ? 0 : m_items.size();
    }

    public String getDatabaseId()
    {
        return databaseId;
    }

    public String getId()
    {
        return dictId;
    }

    public String getName()
    {
        return dictName;
    }

    public ReportDictTypes getDictType()
    {
        return dictType == null ? ReportDictTypes.External : dictType;
    }

    public String getParentId()
    {
        return parentId;
    }

    public String getSqlStatement()
    {
        return sqlStatement;
    }

    public DataTypes getKeyDataType()
    {
        return this.m_keyDataType == null ? DataTypes.STRING : this.m_keyDataType;
    }

    public void setSqlStatement(String sqlStatement)
    {
        this.sqlStatement = sqlStatement;
    }

    public void setParentId(String id)
    {
        this.parentId = id == null ? null : id.trim().toLowerCase();
    }

    public void setDictType(ReportDictTypes dictType)
    {
        this.dictType = dictType;
    }

    public void setName(String dictName)
    {
        this.dictName = dictName;
    }

    public void setId(String id)
    {
        this.dictId = id == null ? null : id.trim().toLowerCase();
    }

    public void setDatabaseId(String databaseId)
    {
        this.databaseId = databaseId;
    }

    public void setKeyDataType(DataTypes d)
    {
        this.m_keyDataType = d;
    }

    public String toString()
    {
        return this.getName() + "[" + this.getId() + "]";
    }

    public void afterInitializedFromXML(XMLNode nodeItem)
        throws ModelException
    {
        if(this.getDictType().equals(ReportDictTypes.SQLTree))
        {
            //#NULL#|City:CityName|Country:CountryName
            if(null == this.m_appendParam)
            {
                String strRootId = nodeItem.subItemOrValueOf("root","rootid","rootkey");
                StringBuffer buf = new StringBuffer();
                buf.append(strRootId == null ? DictItemCollection.NULL : strRootId);
                for(XMLNode level : nodeItem.selectNodes("level","lv"))
                {
                    String strName = level.valueOf("name","title","desc");
                    String strKey = level.valueOf("id","key");
                    if(null != strKey)
                    {
                        buf.append("|" + strKey + ":" + (null == strName ? "" : strName));
                    }
                }
                this.m_appendParam = buf.toString();
            }
        }
        if(getDictType().equals(ReportDictTypes.External))
        {
            DictItemCollection items = new DictItemCollection(this.getKeyDataType());
            for(XMLNode node : nodeItem.selectNodes("item","data"))
            {
                String strKey = node.subItemOrValueOf("id","key");
                String strName = node.subItemOrValueOf("name","title");
                String strParentId = node.subItemOrValueOf("parentId","pid","parent","parentkey");
                if(null == strKey)
                {
                    continue;
                }
                DictItem item = new DictItem(this.getKeyDataType().castValue(strParentId),
                                             this.getKeyDataType().castValue(strKey),strName);
                items.addElement(item);
            }
            if(items.size() < 1)
            {
                throw new ModelException.GeneralException(this +": dict defination error, can not found any items in this dict");
            }
            this.setDictItems(items);
        }
    }

    public void afterInitializedFromJSON(JSONClass nodeItem)
        throws ModelException
    {
        if(getDictType().equals(ReportDictTypes.External))
        {
            DictItemCollection items = new DictItemCollection(this.getKeyDataType());
            JSONArray itemsNode = (JSONArray) nodeItem.getNode("items");
            for(int n = 0;null != itemsNode && n < itemsNode.size();n++)
            {
                JSONClass node = (JSONClass) itemsNode.getItem(n);
                String strKey = node.valueOf("id","key");
                String strName = node.valueOf("name","title");
                String strParentId = node.valueOf("parentId","pid","parent","parentkey");
                if(null == strKey)
                {
                    continue;
                }
                DictItem item = new DictItem(this.getKeyDataType().castValue(strParentId),
                                             this.getKeyDataType().castValue(strKey),strName);
                items.addElement(item);

            }
            if(items.size() < 1)
            {
                throw new ModelException.GeneralException(this +": dict defination error, can not found any items in this dict");
            }
            this.setDictItems(items);
        }
    }

    public void validate()
        throws ModelException
    {
        if(this.getDictType().equals(ReportDictTypes.SQLTree)
           || this.getDictType().equals(ReportDictTypes.SQL))
        {
            if(Algorithms.isEmpty(this.getDatabaseId()))
            {
                throw new ModelException.MissingMandatoryField(this.getClass(),"DatabaseId");
            }
            if(Algorithms.isEmpty(this.getSqlStatement()))
            {
                throw new ModelException.MissingMandatoryField(this.getClass(),"SQL");
            }
        }

    }

    public void afterConvertToXML(XMLNode returnNode)
        throws ModelException
    {
        if(null == returnNode)
        {
            return;
        }
        if(getDictType().equals(ReportDictTypes.External))
        {
            for(DictItem item : this.getItems())
            {
                returnNode.addNode("item").addAttribute("id",item.getKey()
                    ,"name",item.getName()
                    ,"parentId",item.getParentKey());
            }
        }
    }

    public void afterConvertToJSON(JSONClass returnNode)
        throws ModelException
    {
        if(null == returnNode)
        {
            return;
        }
        if(getDictType().equals(ReportDictTypes.External))
        {
            JSONArray ary = new JSONArray();
            returnNode.set("items",ary);
            for(DictItem item : this.getItems())
            {
                ary.add((new JSONClass())
                        .set("id",item.getKey()
                             ,"name",item.getName()
                             ,"parentId",item.getParentKey()));
            }
        }
    }

}
